/*
 *    Copyright (c) 2018-2025, st All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: st
 */
package com.mkh.st.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mkh.st.admin.api.dto.TenantDTO;
import com.mkh.st.admin.api.entity.*;
import com.mkh.st.admin.api.vo.TenantSaveVO;
import com.mkh.st.admin.api.vo.TenantVO;
import com.mkh.st.admin.mapper.StSnMapper;
import com.mkh.st.admin.mapper.SysRoleMenuMapper;
import com.mkh.st.admin.mapper.SysTenantMapper;
import com.mkh.st.admin.mapper.SysUserMapper;
import com.mkh.st.admin.service.*;
import com.mkh.st.common.core.constant.CommonConstants;
import com.mkh.st.common.core.constant.enums.*;
import com.mkh.st.common.core.exception.BizException;
import com.mkh.st.common.core.util.R;
import com.mkh.st.common.security.service.DaoismUser;
import com.mkh.st.common.security.util.SecurityUtils;
import com.mkh.st.product.api.feign.IProductFeignProvider;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 租户
 *
 * @author st
 * @date 2019-05-15 15:55:41
 */
@Service
@AllArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {

	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

	private final SysTenantMapper sysTenantMapper;

	private final StSnMapper stSnMapper;

	private final SysUserMapper sysUserMapper;

	private final SysRoleService sysRoleService;

	private final SysUserRoleService sysUserRoleService;

	private final SysRoleMenuMapper sysRoleMenuMapper;

	private final SysPermissionScopeService sysPermissionScopeService;

	private final SysUserRoleScopeService sysUserRoleScopeService;

	private final IProductFeignProvider feignProvider;

	@Override
	public R<IPage<TenantDTO>> getSysTenantPage(Page page, TenantVO vo) {
		IPage<SysTenant> iPage = sysTenantMapper.selectPage(page,Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getDelFlag, CommonConstants.NOT_DEL)
				.like(StrUtil.isNotBlank(vo.getTenantCode()),SysTenant::getTenantCode,vo.getTenantCode())
				.like(StrUtil.isNotBlank(vo.getTenantName()),SysTenant::getTenantName,vo.getTenantName())
				.orderByDesc(SysTenant::getId));
		IPage<TenantDTO> iPageInfo = new Page<>();
		if(CollectionUtil.isEmpty(iPage.getRecords())){
			return R.ok(iPageInfo);
		}
		List<TenantDTO> list=new ArrayList<>();
		iPage.getRecords().forEach(entity -> {
			TenantDTO dto = BeanUtil.toBean(entity, TenantDTO.class);
			dto.setStatusName(DataStatusEnum.get(entity.getStatus()).getDescription());
			list.add(dto);
		});
		iPageInfo.setRecords(list).setTotal(iPage.getTotal()).setSize(iPage.getSize()).setCurrent(iPage.getCurrent()).setPages(iPage.getPages());
		return R.ok(iPageInfo);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> saveTenantInfo(TenantSaveVO vo) {
		SysTenant sysTenant=BeanUtil.toBean(vo, SysTenant.class);
		LocalDateTime now = LocalDateTime.now();
		if(ObjectUtil.isNotNull(vo.getId())){//修改
			SysTenant exist=sysTenantMapper.selectById(vo.getId());
			List<SysTenant> list = sysTenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getTenantName,vo.getTenantName()).ne(SysTenant::getId,vo.getId())
				.eq(SysTenant::getDelFlag,CommonConstants.NOT_DEL));
			if(CollectionUtil.isNotEmpty(list)){
				throw new BizException(ResultCodeEnum.TENANT_NAME_EXIST);
			}
			List<SysTenant> codeList = sysTenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getTenantCode,vo.getTenantCode()).ne(SysTenant::getId,vo.getId())
				.eq(SysTenant::getDelFlag,CommonConstants.NOT_DEL));
			if(CollectionUtil.isNotEmpty(codeList)){
				throw new BizException(ResultCodeEnum.TENANT_CODE_EXIST);
			}
			sysTenant.setUpdateTime(now);
			if(sysTenantMapper.updateById(sysTenant)==CommonConstants.ZERO){
				throw new BizException(ResultCodeEnum.SAVE_TENANT_FAIL);
			}
			List<SysUser> userList=sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
				.eq(SysUser::getPhone,vo.getPhoneNumber()).eq(SysUser::getDelFlag,CommonConstants.ZERO)
				.ne(SysUser::getUserId,exist.getUserId()));
			if(CollectionUtil.isNotEmpty(userList)){
				throw new BizException(ResultCodeEnum.TENANT_PHONE_EXIST);
			}
			SysUser sysUser=new SysUser();
			sysUser.setUserId(exist.getUserId());
			sysUser.setPhone(vo.getPhoneNumber());
			sysUser.setUsername(vo.getContact());
			sysUserMapper.updateById(sysUser);
		}else {//新增
			DaoismUser user = SecurityUtils.getUser();
			SysUser existUser=sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
					.eq(SysUser::getPhone,vo.getPhoneNumber()).eq(SysUser::getDelFlag,CommonConstants.ZERO));
			if(ObjectUtil.isNotNull(existUser)){
				throw new BizException(ResultCodeEnum.TENANT_PHONE_EXIST);
			}
			List<SysTenant> list = sysTenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getTenantName,vo.getTenantName())
				.eq(SysTenant::getDelFlag,CommonConstants.NOT_DEL));
			if(CollectionUtil.isNotEmpty(list)){
				throw new BizException(ResultCodeEnum.TENANT_NAME_EXIST);
			}
			List<SysTenant> codeList = sysTenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getTenantCode,vo.getTenantCode())
				.eq(SysTenant::getDelFlag,CommonConstants.NOT_DEL));
			if(CollectionUtil.isNotEmpty(codeList)){
				throw new BizException(ResultCodeEnum.TENANT_CODE_EXIST);
			}
			sysTenant.setCreateTime(now).setDelFlag(CommonConstants.NOT_DEL);
			if(sysTenantMapper.insert(sysTenant)==CommonConstants.ZERO){
				throw new BizException(ResultCodeEnum.SAVE_TENANT_FAIL);
			}
			//生成单据编码
			StSn stSn=new StSn();
			stSn.setTenantId(sysTenant.getId()).setCreateBy(user.getName()).setCreateId(user.getId()).setCreateTime(now);
			if(!stSnMapper.insertFromSelect(stSn)){
				throw new BizException(100,"保存租户失败!");
			}
			//生成用户信息
			SysUser sysUser=new SysUser();
			sysUser.setUsername(vo.getContact()).setPassword(ENCODER.encode(CommonConstants.DEFAULT_PASSWORD))
				.setPhone(vo.getPhoneNumber()).setDelFlag(CommonConstants.NOT_DEL).setCreateBy(user.getName())
				.setCreateId(user.getId()).setCreateTime(now).setBeginTime(now).setEndTime(LocalDateTime.of(2099,12,31,23,59,59))
				.setNormalFlag(CommonConstants.ONE).setUserBusinessType(UserBusinessTypeEnum.OTHER.getCode())
				.setUserType(UserTypeEnum.TENANT_USER.getCode()).setTenantId(sysTenant.getId())
				.setSex(SexEnum.UNKNOWN.getStatus()).setNotShow(CommonConstants.NOT_DEL);
			if(sysUserMapper.insert(sysUser)==CommonConstants.ZERO){
				throw new BizException(200,"保存租户失败!");
			}
			//按角色模板生成租户角色
			SysRole entity=new SysRole();
			entity.setSysFlag(CommonConstants.ZERO).setTenantId(sysTenant.getId()).setStatus(CommonConstants.ONE)
					.setDelFlag(CommonConstants.NOT_DEL).setRoleName(RoleLevelEnum.ZERO.getDescription())
					.setRoleCode(RoleLevelEnum.ONE.getRoleCode()).setSysFlag(RoleLevelEnum.ONE.getCode())
					.setParentId(-1L).setCreateBy(user.getName()).setCreateId(user.getId()).setCreateTime(now)
					.setResource(RoleLevelEnum.ONE.getResource());
			if(!sysRoleService.save(entity)){
				throw new BizException(201,"保存租户失败!");
			}
			//租户用户和角色关联
			SysUserRole sysUserRole=new SysUserRole(sysUser.getUserId(),entity.getRoleId());
			if(!sysUserRoleService.save(sysUserRole)){
				throw new BizException(202,"保存租户失败!");
			}
			//新建的角色和菜单按钮关联
			SysRole sysRole=sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery()
					.eq(SysRole::getRoleCode, RoleLevelEnum.ONE.getRoleCode()).eq(SysRole::getTenantId,CommonConstants.ZERO));
			if(!sysRoleMenuMapper.insertFromSelect(entity.getRoleId(),sysRole.getRoleId())){
				throw new BizException(203,"保存租户失败!");
			}
			// 添加数据权限
			List<SysPermissionScope> permissions = sysPermissionScopeService.list();
			List<SysUserRoleScope> scopeList=new ArrayList<>();
			permissions.forEach(item ->{
				SysUserRoleScope scope=new SysUserRoleScope();
				scope.setUserId(sysUser.getUserId()).setRoleId(entity.getRoleId())
						.setAllFlag(CommonConstants.ONE).setScopeId(item.getScopeId());
				scopeList.add(scope);
			});
			if(!sysUserRoleScopeService.saveBatch(scopeList)){
				throw new BizException(204,"保存租户失败!");
			}
			sysTenant.setUserId(sysUser.getUserId());
			sysTenantMapper.updateById(sysTenant);
			feignProvider.autoCreateWeightUnit(sysTenant.getId());

		}
		return R.ok(Boolean.TRUE);
	}

	@Override
	public List<SysTenant> getNormallist() {
		return sysTenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery()
				.eq(SysTenant::getStatus,CommonConstants.ONE)
				.eq(SysTenant::getDelFlag,CommonConstants.NOT_DEL));
	}
//	/**
//	 * 获取正常状态租户
//	 * <p>
//	 * 1. 状态正常 2. 开始时间小于等于当前时间 3. 结束时间大于等于当前时间
//	 * @return
//	 */
//	@Override
//	@Cacheable(value = CacheConstants.TENANT_DETAILS)
//	public List<SysTenant> getNormalTenant() {
//		return baseMapper
//				.selectList(Wrappers.<SysTenant>lambdaQuery().eq(SysTenant::getStatus, CommonConstants.STATUS_NORMAL));
//	}
//
//	/**
//	 * 保存租户
//	 * <p>
//	 * 1. 保存租户 2. 初始化权限相关表 - sys_user - sys_role - sys_menu - sys_user_role -
//	 * sys_role_menu - sys_dict - sys_dict_item - sys_client_details - sys_public_params
//	 * @param sysTenant 租户实体
//	 * @return
//	 */
//	@Override
//	@Transactional(rollbackFor = Exception.class)
//	@CacheEvict(value = CacheConstants.TENANT_DETAILS)
//	public Boolean saveTenant(SysTenant sysTenant) {
//		this.save(sysTenant);
//		// 查询系统默认租户配置参数
//		Integer defaultId = ParamResolver.getInt("TENANT_DEFAULT_ID", 1);
//		String defaultDeptName = ParamResolver.getStr("TENANT_DEFAULT_DEPTNAME", "租户默认部门");
//		String defaultUsername = ParamResolver.getStr("TENANT_DEFAULT_USERNAME", "admin");
//		String defaultPassword = ParamResolver.getStr("TENANT_DEFAULT_PASSWORD", "123456");
//		String defaultRoleCode = ParamResolver.getStr("TENANT_DEFAULT_ROLECODE", "ROLE_ADMIN");
//		String defaultRoleName = ParamResolver.getStr("TENANT_DEFAULT_ROLENAME", "租户默认角色");
//
//		List<SysDict> dictList = new ArrayList<>(32);
//		List<Integer> dictIdList = new ArrayList<>(32);
//		List<SysDictItem> dictItemList = new ArrayList<>(64);
//		List<SysMenu> menuList = new ArrayList<>(128);
//		List<SysOauthClientDetails> clientDetailsList = new ArrayList<>(16);
//		List<SysPublicParam> publicParamList = new ArrayList<>(64);
//
//		TenantBroker.runAs(defaultId, (id) -> {
//			// 查询系统内置字典
//			dictList.addAll(dictService.list());
//			// 查询系统内置字典项目
//			dictIdList.addAll(dictList.stream().map(SysDict::getId).collect(Collectors.toList()));
//			dictItemList.addAll(
//					dictItemService.list(Wrappers.<SysDictItem>lambdaQuery().in(SysDictItem::getDictId, dictIdList)));
//			// 查询当前租户菜单
//			menuList.addAll(menuService.list());
//			// 查询客户端配置
//			clientDetailsList.addAll(clientServices.list());
//			// 查询系统参数配置
//			publicParamList.addAll(paramService.list());
//		});
//
//		// 保证插入租户为新的租户
//		return TenantBroker.applyAs(sysTenant.getId(), (id -> {
//
//			// 插入部门
//			SysDept dept = new SysDept();
//			dept.setName(defaultDeptName);
//			dept.setParentId(0);
//			deptService.save(dept);
//			// 维护部门关系
//			deptRelationService.insertDeptRelation(dept);
//			// 构造初始化用户
//			SysUser user = new SysUser();
//			user.setUsername(defaultUsername);
//			user.setPassword(ENCODER.encode(defaultPassword));
//			user.setDeptId(dept.getDeptId());
//			userService.save(user);
//			// 构造新角色
//			SysRole role = new SysRole();
//			role.setRoleCode(defaultRoleCode);
//			role.setRoleName(defaultRoleName);
//			roleService.save(role);
//			// 用户角色关系
//			SysUserRole userRole = new SysUserRole();
//			userRole.setUserId(user.getUserId());
//			userRole.setRoleId(role.getRoleId());
//			userRoleService.save(userRole);
//			// 插入新的菜单
//			saveTenantMenu(TreeUtil.buildTree(menuList, CommonConstants.MENU_TREE_ROOT_ID),
//					CommonConstants.MENU_TREE_ROOT_ID);
//			List<SysMenu> newMenuList = menuService.list();
//
//			// 查询全部菜单,构造角色菜单关系
//			List<SysRoleMenu> roleMenuList = newMenuList.stream().map(menu -> {
//				SysRoleMenu roleMenu = new SysRoleMenu();
//				roleMenu.setRoleId(role.getRoleId());
//				roleMenu.setMenuId(menu.getMenuId());
//				return roleMenu;
//			}).collect(Collectors.toList());
//			roleMenuMapper.insertBatchSomeColumn(roleMenuList);
//			// 插入系统字典
//			dictService.saveBatch(dictList);
//			// 处理字典项最新关联的字典ID
//			List<SysDictItem> itemList = dictList.stream().flatMap(dict -> dictItemList.stream()
//					.filter(item -> item.getType().equals(dict.getType())).peek(item -> item.setDictId(dict.getId())))
//					.collect(Collectors.toList());
//
//			// 插入客户端
//			clientServices.saveBatch(clientDetailsList);
//			// 插入系统配置
//			paramService.saveBatch(publicParamList);
//			return dictItemService.saveBatch(itemList);
//		}));
//
//	}
//
//
//
//    /**
//	 * 保存新的租户菜单，维护成新的菜单
//	 * @param nodeList 节点树
//	 * @param parent 上级
//	 */
//	private void saveTenantMenu(List<MenuTree> nodeList, Integer parent) {
//		for (MenuTree node : nodeList) {
//			SysMenu menu = new SysMenu();
//			BeanUtils.copyProperties(node, menu, "parentId");
//			menu.setParentId(parent);
//			menuService.save(menu);
//			if (CollUtil.isNotEmpty(node.getChildren())) {
//				List<MenuTree> childrenList = node.getChildren().stream().map(treeNode -> (MenuTree) treeNode)
//						.collect(Collectors.toList());
//				saveTenantMenu(childrenList, menu.getMenuId());
//			}
//		}
//	}

}
